/**
 * Created by spatra on 14-9-8.
 */

define(['QUnit', 'app/physicsengine', 'app/entity'], function(QUnit, PhysicsEngine, Entity){

	var initStatus = {
		canvasWidth: 1200,
		canvasHeight: 700,
		gridSize: 40,
		friction: 0.8,
		gravity: 0.3
	};

	var run = function(){

		function buildPhysicsEngine(){
			return new PhysicsEngine(initStatus.canvasWidth, initStatus.canvasHeight,
				initStatus.gridSize,
				initStatus.friction, initStatus.gravity);
		}

		var MockEntity = function(radius, x, y){
			this.radius = radius;
			this.x = x;
			this.y = y;
			this.collision = false;
		};

		function buildMockEntities(num, theEngine){
			var entities = [];

			var canvasWidth = theEngine.canvasWidth;
			var canvasHeight = theEngine.canvasHeight;

			for( var i = 0; i < num; ++i ){
				entities.push(
					new MockEntity( Math.random() * 5 >> 0,
							Math.random() * canvasWidth,
							Math.random() * canvasHeight )
				);
			}

			return entities;
		}

		QUnit.module('PhysicsEngine');

		QUnit.test('测试PhysicsEngine构造函数', function(assert){

			var theEngine = new PhysicsEngine(initStatus.canvasWidth, initStatus.canvasHeight, initStatus.gridSize);

			assert.equal(theEngine.canvasWidth, initStatus.canvasWidth, '画布宽度');
			assert.equal(theEngine.canvasHeight, initStatus.canvasHeight, '画布高度');

			assert.ok( Object.prototype.toString.call(theEngine.grids) === '[object Array]', '分格数组');
			assert.equal(theEngine.gridSize, initStatus.gridSize, '分格的大小');
			assert.equal(theEngine.xGrids, (theEngine.canvasWidth / theEngine.gridSize >> 0) + 2, '横向格子的数目');
			assert.equal(theEngine.yGrids, (theEngine.canvasHeight / theEngine.gridSize >> 0) + 2, '纵向格子的数目');

			assert.equal(theEngine.friction, 0.9, '模拟摩擦力系数（默认值）');
			assert.equal(theEngine.gravity, 0, '模拟重力系数（默认值)');

			theEngine = buildPhysicsEngine();

			assert.equal(theEngine.friction, initStatus.friction, '模拟摩摩擦力系数');
			assert.equal(theEngine.gravity, initStatus.gravity, '模拟重力系数');
		});

		QUnit.test('测试PhysicsEngine类的分格初始化', function(assert){
			var theEngine = buildPhysicsEngine();

			theEngine._makeGrids();
			assert.equal(theEngine.grids.length, theEngine.xGrids, '水平方向格子的数目');
			assert.equal(theEngine.grids[0].length, theEngine.yGrids, '竖直方向上格子的数目');

			var theMockEntity = new MockEntity(5, theEngine.gridSize + 1, theEngine.gridSize + 5);
			assert.deepEqual( theEngine._getGridsPosition(theMockEntity), {x: 1, y: 1}, '查询实体所在的格子的坐标');

			var numEntities = 30;
			theEngine._initGrids( buildMockEntities(numEntities, theEngine) );

			assert.equal( (function(){
					var sum = 0;
					for(var i = 0; i < theEngine.grids.length; ++i ){
						for( var j = 0; j < theEngine.grids[i].length; ++j){
							sum += theEngine.grids[i][j].length;
						}
					}
					return sum;
			})(),
			numEntities, '实体放到格子中');

			QUnit.test('测试PhysicsEngine对格子中的实体的碰撞检测', function(assert) {
				var theEngine = buildPhysicsEngine();

				var entityA = new MockEntity(5, 4, 10),
					entityB = new MockEntity(5, 10, 17);

				var bumpedEntities = [];
				theEngine._makeGrids();
				theEngine._initGrids( [entityA, entityB] );
				theEngine._checkOneGrid(0, 0, bumpedEntities);
				assert.notEqual(bumpedEntities.length, 0, '检测到碰撞, bumpedEntities数组不为空(checkOneGrid)');
				var result = bumpedEntities.pop();
				assert.ok( result.entityA.collision && result.entityB.collision, '碰撞(checkOneGrid)');

				entityB.x = entityA.x + theEngine.gridSize;
				entityB.y = entityA.y + theEngine.gridSize;
				theEngine._makeGrids();
				theEngine._initGrids( [entityA, entityB] );
				theEngine._checkOneGrid(0, 0, bumpedEntities);
				assert.equal( bumpedEntities.length, 0, '非碰撞（checkOneGrid)');

				theEngine = buildPhysicsEngine();
				entityA = new MockEntity(5, theEngine.gridSize - 4, theEngine.gridSize - 2);
				entityB = new MockEntity(5, theEngine.gridSize +1, theEngine.gridSize + 5);
				theEngine._makeGrids();
				theEngine._initGrids( [ entityA, entityB] );
				theEngine._checkTwoGrid(0, 0, 1, 1, bumpedEntities);
				assert.notEqual(bumpedEntities.length, 0, '检测到碰撞, bumpedEntities数组不为空(checkTwoGrid)');
				result = bumpedEntities.pop();
				assert.ok( result.entityA.collision && result.entityB.collision, '碰撞(checkTwoGrid)');

				entityB.x = theEngine.gridSize + 6 ;
				entityB.y = theEngine.gridSize + 8;
				theEngine._makeGrids();
				theEngine._initGrids( [ entityA, entityB] );
				theEngine._checkTwoGrid(0, 0, 1, 1, bumpedEntities);
				assert.equal(bumpedEntities.length, 0, '非碰撞(checkTwoGrid)');

				entityA = new MockEntity(5, theEngine.gridSize - 4, theEngine.gridSize - 2);
				entityB = new MockEntity(5, theEngine.gridSize +1, theEngine.gridSize + 5);
				bumpedEntities = theEngine.checkCollision([entityA, entityB]);
				assert.notEqual(bumpedEntities.length, 0, '检测到碰撞， bumpedEntities数组不为空(checkCollision, 不同格子)')
				result = bumpedEntities.pop();
				assert.ok( result.entityA.collision && result.entityB.collision, '碰撞(checkCollision, 不同格子)');

				entityA = new MockEntity(5, 4, 10);
				entityB = new MockEntity(5, 10, 17);
				bumpedEntities = theEngine.checkCollision([entityA, entityB]);
				assert.notEqual(bumpedEntities.length, 0, '检测到碰撞， bumpedEntities数组不为空(checkCollision, 同一格子)')
				result = bumpedEntities.pop();
				assert.ok(  result.entityA.collision && result.entityB.collision, '碰撞(checkCollision, 同一格子)');

			});

			QUnit.test('测试的PhysicsEngine对实体的移动', function(assert){
				var theEngine = buildPhysicsEngine();

				var startX = 10, startY = 10, startVx = 10, startVy = 10;
				var theEntity = new Entity(5, startX, startY, 10, 10, 0, 2);  //此处使用真实的Entity对象
				var step = 10;
				for(var i = 0; i < step; ++i ){
					theEngine.calculateNewPosition([theEntity]);
				}
				assert.equal(theEntity.x, startX + startVx * step + 0.5 * theEntity.ax * Math.pow(step, 2), '计算x轴的坐标(不碰到边界)');
				assert.equal(theEntity.y, startY + startVy * step + 0.5 * theEntity.ay * Math.pow(step, 2), '计算y轴的坐标(不碰到边界)');



			});

		});
	};

	return {
		run: run
	};
});